/*
 * @Author: wangchao
 * @Date: 2024-10-04 12:07:03
 * @LastEditors: wangchao
 * @LastEditTime: 2024-10-05 09:12:49
 * @FilePath: \JD-RTT-Driver\applications\u_ai.c
 * @Description:
 * Copyright (c) 2024 by Bingshan Guardian, All Rights Reserved.
 */
#include <rtthread.h>
#include <rtdevice.h>
#include "board.h"
#include "board.h"
#include "u_utilits.h"
#include "u_data.h"

#define DBG_TAG "AI"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#define ANG_PCA555_I2C_BUS                 "i2c1"
#define ANG_PCA555_ADDR                    0x24
#define ai_get_low_byte(value)             ((uint8_t)((value)&0xff))
#define ai_get_high_byte(value)            ((uint8_t)((value) >> 8))
#define ai_bit_set(value, bit)             ((value) |= (1UL << (bit)))
#define ai_bit_clear(value, bit)           ((value) &= ~(1UL << (bit)))
#define ai_bit_write(value, bit, bitvalue) (bitvalue ? ai_bit_set(value, bit) : ai_bit_clear(value, bit))

static struct rt_i2c_bus_device* ai_i2c_bus = RT_NULL;
static rt_bool_t ai_initialized = RT_FALSE;
static rt_uint16_t ai_port_value = 0;

static rt_err_t ai_write_reg(struct rt_i2c_bus_device* bus, rt_uint8_t dev_addr, rt_uint8_t reg, rt_uint8_t* data)
{
    rt_uint8_t buf[3];
    struct rt_i2c_msg msgs;
    rt_uint32_t buf_size = 1;

    buf[0] = reg;
    if (data != RT_NULL)
    {
        buf[1] = data[0];
        buf[2] = data[1];
        buf_size = 3;
    }

    msgs.addr = dev_addr;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = buf_size;

    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return RT_ERROR;
    }
}

static void ai_pca555_set_port(rt_uint8_t* value, rt_uint8_t pin)
{
    if (pin >= 0 || pin < 16)
    {
        ai_bit_write(ai_port_value, pin, 1);
        value[0] = ai_get_low_byte(ai_port_value);
        value[1] = ai_get_high_byte(ai_port_value);
    }
}

static void ai_pca555_reset_port(rt_uint8_t* value, rt_uint8_t pin)
{
    if (pin >= 0 || pin < 16)
    {
        ai_bit_write(ai_port_value, pin, 0);
        value[0] = ai_get_low_byte(ai_port_value);
        value[1] = ai_get_high_byte(ai_port_value);
    }
}

static int ai_pca555_init()
{
    rt_uint8_t temp[2] = {0, 0};
    rt_uint8_t index = 0;

    rt_kprintf("analog pca555 init start!\n");

    ai_i2c_bus = (struct rt_i2c_bus_device*)rt_device_find(ANG_PCA555_I2C_BUS);

    if (ai_i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", ANG_PCA555_I2C_BUS);
        return RT_ERROR;
    }

    // 配置IO端口输出模式
    temp[0] = 0x00;
    temp[1] = 0x00;
    ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x06, temp);
    for (index = 0; index < 16; index++)
    {
        ai_pca555_reset_port(temp, index);
        ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
    }

    ai_initialized = RT_TRUE;
}

INIT_COMPONENT_EXPORT(ai_pca555_init);

#define PinA 0u
#define PinB 1u
static void analog_select_chip(rt_uint8_t chan)
{
    rt_uint8_t temp[2] = {0, 0};
    /*
            A-P0        B-P1
            0           0           x0-y0
            1           0           x1-y1
            0           1           x2-y2
            1           1           x3-y3
    */
    if (chan == 0)
    {
        // 2
        ai_pca555_reset_port(temp, PinA);
        ai_pca555_reset_port(temp, PinB);
        ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
        return;
    }
    else if (chan == 1)
    {
        ai_pca555_set_port(temp, PinA);
        ai_pca555_reset_port(temp, PinB);
        ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
        return;
    }
    else if (chan == 2)
    {
        ai_pca555_reset_port(temp, PinA);
        ai_pca555_set_port(temp, PinB);
        ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
        return;
    }
    else if (chan == 3)
    {
        ai_pca555_set_port(temp, PinA);
        ai_pca555_set_port(temp, PinB);
        ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
        return;
    }
}

void mcp_select_chip(rt_uint8_t chan)
{
    rt_uint8_t temp[2] = {0, 0};
    if (chan == 1)
    {
        ai_pca555_reset_port(temp, 6);
        ai_pca555_reset_port(temp, 7);
    }
    else if (chan == 2)
    {
        ai_pca555_set_port(temp, 6);
        ai_pca555_set_port(temp, 7);
    }
    ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
}

/**
 **************** ADS7822u 驱动部分 *************************
 */
/**
 *  ADS7822器件端口定义部分
 */
#define ANG_SCK_P           GET_PIN(C, 2)
#define ANG_DOUT_P          GET_PIN(C, 3)
#define ANG_ADS_DOUT_READ() rt_pin_read(ANG_DOUT_P)

#define ANG_ADCS_1P 5u
#define ANG_ADCS_2P 3u
#define ANG_ADCS_3P 2u

static void ads_gpio_init(void)
{
    rt_pin_mode(ANG_SCK_P, PIN_MODE_OUTPUT_OD);
    rt_pin_mode(ANG_DOUT_P, PIN_MODE_INPUT_PULLUP);
}

static void ads_csp_ctrl(rt_uint8_t chx, rt_uint8_t val)
{
    rt_uint8_t temp[2] = {0, 0};
    rt_uint8_t addr[3] = {ANG_ADCS_2P, ANG_ADCS_1P, ANG_ADCS_3P};
    if (val)
    {
        ai_pca555_set_port(temp, addr[chx]);
    }
    else
    {
        ai_pca555_reset_port(temp, addr[chx]);
    }
    ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
}

static void bsp_delay(void)
{
    uint8_t i;
    for (i = 0; i < 3; i++)
        ;
}

static rt_uint16_t ads_get_adc_value(rt_uint8_t chx)
{
    rt_uint8_t i;
    rt_uint16_t data = 0;
    // CS->1
    ads_csp_ctrl(chx, 1);
    bsp_delay();
    rt_pin_write(ANG_SCK_P, PIN_LOW);
    // CS->0
    ads_csp_ctrl(chx, 0);
    for (i = 0; i < 15; i++)
    {
        rt_pin_write(ANG_SCK_P, PIN_HIGH);
        bsp_delay();
        if (ANG_ADS_DOUT_READ())
        {
            data |= 1;
        }
        rt_pin_write(ANG_SCK_P, PIN_LOW);
        bsp_delay();
        data = data << 1;
    }
    // CS->1
    ads_csp_ctrl(chx, 1);
    return data & 0x0FFF;
}

#define CD_PinA 11u
#define CD_PinB 12u
#define CD_PinC 13u

void cd4501_select_chx(rt_uint8_t chx)
{
    rt_uint8_t temp[2] = {0, 0};
    switch (chx)
    {
        case 0:
            // 000
            ai_pca555_reset_port(temp, CD_PinA);
            ai_pca555_reset_port(temp, CD_PinB);
            ai_pca555_reset_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        case 1:
            // 001
            ai_pca555_set_port(temp, CD_PinA);
            ai_pca555_reset_port(temp, CD_PinB);
            ai_pca555_reset_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        case 2:
            // 010
            ai_pca555_reset_port(temp, CD_PinA);
            ai_pca555_set_port(temp, CD_PinB);
            ai_pca555_reset_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        case 3:
            // 011
            ai_pca555_set_port(temp, CD_PinA);
            ai_pca555_set_port(temp, CD_PinB);
            ai_pca555_reset_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        case 4:
            // 100
            ai_pca555_reset_port(temp, CD_PinA);
            ai_pca555_reset_port(temp, CD_PinB);
            ai_pca555_set_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        case 5:
            // 101
            ai_pca555_set_port(temp, CD_PinA);
            ai_pca555_reset_port(temp, CD_PinB);
            ai_pca555_set_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        case 6:
            // 110
            ai_pca555_reset_port(temp, CD_PinA);
            ai_pca555_set_port(temp, CD_PinB);
            ai_pca555_set_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        case 7:
            // 111
            ai_pca555_set_port(temp, CD_PinA);
            ai_pca555_set_port(temp, CD_PinB);
            ai_pca555_set_port(temp, CD_PinC);
            ai_write_reg(ai_i2c_bus, ANG_PCA555_ADDR, 0x02, temp);
            break;
        default:
            break;
    }
}

/**
 *  系统传感器数据
 */
sensor_data app_sensor_data;
//
AI_Param ADC1_AIS[8];
AI_Param ADC2_AIS[8];
AI_Param ADC3_AIS[8];

void ai_sensor_detect_thread_entry(void)
{
    rt_int32_t value = 0;
    rt_uint8_t index;
    rt_uint8_t loop, chan;
    float f_temp = 0.0;

    ads_gpio_init();
    rt_thread_mdelay(20);

    while (1)
    {
        for (chan = 0; chan < 3; chan++)
        {
            // 通讯线切换开关
            analog_select_chip(chan);
            rt_thread_mdelay(5);
            for (index = 0; index < 5; index++)
            {
                // 模拟开关切换通道
                cd4501_select_chx(index);
                rt_thread_mdelay(100);
                value = 0;
                // 均值滤波
                for (loop = 0; loop < 3; loop++)
                {
                    value += ads_get_adc_value(chan);
                }
                value = value / 3;
                if (chan == 0)
                {
                    // ADC1 - CHANNEL
                    ADC1_AIS[index].adc_value = value;
                    f_temp = (float)(ADC1_AIS[index].vol_gain / 1000.0);
                    //
                    rt_int16_t tv = (rt_int16_t)((ADC1_AIS[index].adc_value - ADC1_AIS[index].vol_offset) * f_temp);
                    ADC1_AIS[index].vol_value = tv;

                    f_temp = (ADC1_AIS[index].vol_value / 1000.0 - ADC1_AIS[index].vol_min) / (ADC1_AIS[index].vol_max - ADC1_AIS[index].vol_min);
                    ADC1_AIS[index].phy_value = (f_temp * (float)(ADC1_AIS[index].phy_max - ADC1_AIS[index].phy_min));
                    // ADC-1-REMAP
                    //
                    app_sensor_data.charging_current = ADC1_AIS[0].phy_value;
                    app_sensor_data.discharging_current = ADC1_AIS[3].phy_value;
                    app_sensor_data.electrolyte_temp = ADC1_AIS[2].phy_value;
                }
                if (chan == 1)
                {
                    // ADC2 - CHANNEL
                    ADC2_AIS[index].adc_value = value;
                    f_temp = (float)(ADC2_AIS[index].vol_gain / 1000.0);
                    //
                    rt_int16_t tv = (rt_int16_t)((ADC2_AIS[index].adc_value - ADC2_AIS[index].vol_offset) * f_temp);
                    ADC2_AIS[index].vol_value = tv;

                    f_temp = (float)(ADC2_AIS[index].vol_value / 1000.0 - (float)ADC2_AIS[index].vol_min) / (float)(ADC2_AIS[index].vol_max - ADC2_AIS[index].vol_min);
                    ADC2_AIS[index].phy_value = (f_temp * (float)(ADC2_AIS[index].phy_max - ADC2_AIS[index].phy_min)) + ADC2_AIS[index].phy_min;
                    // ADC-2-REMAP
                    app_sensor_data.b_p_pump_ck_press = ADC2_AIS[3].phy_value;
                    app_sensor_data.a_p_pump_ck_press = ADC2_AIS[0].phy_value;
                    app_sensor_data.bms_humidity = ADC2_AIS[1].phy_value;
                    app_sensor_data.bms_temp = ADC2_AIS[2].phy_value;
                }
                if (chan == 2)
                {
                    // ADC3 - CHANNEL
                    ADC3_AIS[index].adc_value = value;
                    f_temp = (float)(ADC3_AIS[index].vol_gain / 1000.0);
                    //
                    rt_int16_t tv = (rt_int16_t)((ADC3_AIS[index].adc_value - ADC3_AIS[index].vol_offset) * f_temp);
                    ADC3_AIS[index].vol_value = tv;

                    f_temp = (ADC3_AIS[index].vol_value / 1000.0 - ADC3_AIS[index].vol_min) / (ADC3_AIS[index].vol_max - ADC3_AIS[index].vol_min);
                    ADC3_AIS[index].phy_value = (f_temp * (float)(ADC3_AIS[index].phy_max - ADC3_AIS[index].phy_min)) + ADC3_AIS[index].phy_min;
                    // ADC-3-REMAP
                    app_sensor_data.a_n_pump_ck_press = ADC3_AIS[3].phy_value;
                    app_sensor_data.b_n_pump_ck_press = ADC3_AIS[0].phy_value;
                    app_sensor_data.p_gz_press = ADC3_AIS[1].phy_value;
                    app_sensor_data.n_gz_press = ADC3_AIS[2].phy_value;
                }
            }
        }
    }
}

int bms_ai_sensor_detect_thread(void)
{
    rt_thread_t thread_id = RT_NULL;

    // 读取校准参数
    if (get_adc_calibrate_parameters() == RT_FALSE)
    {
        LOG_E("get adc calibrate parameters error!n");
    }
    rt_thread_mdelay(20);
    // 读取传感器量程数据
//    get_sensor_range();
    rt_thread_mdelay(20);

    thread_id = rt_thread_create("ai", (void (*)(void*))ai_sensor_detect_thread_entry, RT_NULL, B_ADC_CVT_STACK_SIZE, B_ADC_CVT_THREAD_PRIORITY, 10);
    if (thread_id != RT_NULL)
    {
        rt_thread_startup(thread_id);
    }
    else
    {
        goto __exit;
    }
    return RT_EOK;

__exit:
    if (thread_id)
        rt_thread_delete(thread_id);
    return RT_ERROR;
}
